import {
  IsString,
  IsEmail,
  IsOptional,
  IsEnum,
  IsBoolean,
  IsArray,
  IsUUID,
  IsInt,
  IsUrl,
  IsDateString,
  IsJWT,
  MinLength,
  MaxLength,
  Min,
  Max,
  Matches,
  ValidateNested,
  ArrayMinSize,
  ArrayMaxSize,
  IsPhoneNumber
} from 'class-validator'
import { Type, Transform, Expose, Exclude } from 'class-transformer'
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger'
import { BaseDto, PaginationDto } from './base.dto'
import { IsStrongPassword, IsValidUsername } from '../validators/custom.validator'
import { UserRole } from '@prisma/client'
import { UserStatus } from './user.dto'

/**
 * 认证提供商枚举
 */
export enum AuthProvider {
  LOCAL = 'local',
  GOOGLE = 'google',
  GITHUB = 'github',
  WECHAT = 'wechat',
  QQ = 'qq',
  WEIBO = 'weibo'
}

/**
 * 会话状态枚举
 */
export enum SessionStatus {
  ACTIVE = 'active',
  EXPIRED = 'expired',
  REVOKED = 'revoked',
  SUSPENDED = 'suspended'
}

/**
 * 设备信息DTO
 */
export class DeviceInfoDto {
  @ApiPropertyOptional({ description: '设备类型' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  type?: string

  @ApiPropertyOptional({ description: '操作系统' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  os?: string

  @ApiPropertyOptional({ description: '浏览器' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  browser?: string

  @ApiPropertyOptional({ description: '设备名称' })
  @IsOptional()
  @IsString()
  @MaxLength(100)
  name?: string

  @ApiPropertyOptional({ description: '设备指纹' })
  @IsOptional()
  @IsString()
  @MaxLength(200)
  fingerprint?: string

  @ApiPropertyOptional({ description: '屏幕分辨率' })
  @IsOptional()
  @IsString()
  @MaxLength(20)
  screenResolution?: string

  @ApiPropertyOptional({ description: '时区' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  timezone?: string

  @ApiPropertyOptional({ description: '语言' })
  @IsOptional()
  @IsString()
  @MaxLength(10)
  language?: string
}

/**
 * 登录DTO
 */
export class LoginDto {
  @ApiProperty({ description: '登录标识符（用户名或邮箱）' })
  @IsString()
  @MinLength(1)
  @MaxLength(100)
  identifier: string

  @ApiProperty({ description: '密码' })
  @IsString()
  @MinLength(1)
  @MaxLength(128)
  password: string

  @ApiPropertyOptional({ description: '记住我' })
  @IsOptional()
  @IsBoolean()
  rememberMe?: boolean

  @ApiPropertyOptional({ description: '验证码' })
  @IsOptional()
  @IsString()
  @MaxLength(10)
  captcha?: string

  @ApiPropertyOptional({ description: '验证码令牌' })
  @IsOptional()
  @IsString()
  captchaToken?: string

  @ApiPropertyOptional({ description: '双因素认证代码' })
  @IsOptional()
  @IsString()
  @Matches(/^\d{6}$/)
  twoFactorCode?: string

  @ApiPropertyOptional({ description: '设备信息' })
  @IsOptional()
  @ValidateNested()
  @Type(() => DeviceInfoDto)
  deviceInfo?: DeviceInfoDto
}

/**
 * 注册DTO
 */
export class RegisterDto {
  @ApiProperty({ description: '用户名' })
  @IsString()
  @IsValidUsername()
  @MinLength(3)
  @MaxLength(30)
  username: string

  @ApiProperty({ description: '邮箱地址' })
  @IsEmail()
  @MaxLength(100)
  email: string

  @ApiProperty({ description: '密码' })
  @IsString()
  @IsStrongPassword()
  @MinLength(8)
  @MaxLength(128)
  password: string

  @ApiProperty({ description: '确认密码' })
  @IsString()
  confirmPassword: string

  @ApiPropertyOptional({ description: '昵称' })
  @IsOptional()
  @IsString()
  @MaxLength(50)
  nickname?: string

  @ApiPropertyOptional({ description: '手机号码' })
  @IsOptional()
  @IsPhoneNumber('CN')
  phone?: string

  @ApiPropertyOptional({ description: '邀请码' })
  @IsOptional()
  @IsString()
  @MaxLength(20)
  inviteCode?: string

  @ApiPropertyOptional({ description: '验证码' })
  @IsOptional()
  @IsString()
  @MaxLength(10)
  captcha?: string

  @ApiPropertyOptional({ description: '验证码令牌' })
  @IsOptional()
  @IsString()
  captchaToken?: string

  @ApiProperty({ description: '同意服务条款' })
  @IsBoolean()
  agreeToTerms: boolean

  @ApiProperty({ description: '同意隐私政策' })
  @IsBoolean()
  agreeToPrivacy: boolean

  @ApiPropertyOptional({ description: '订阅营销邮件' })
  @IsOptional()
  @IsBoolean()
  subscribeNewsletter?: boolean

  @ApiPropertyOptional({ description: '设备信息' })
  @IsOptional()
  @ValidateNested()
  @Type(() => DeviceInfoDto)
  deviceInfo?: DeviceInfoDto
}

/**
 * 刷新令牌DTO
 */
export class RefreshTokenDto {
  @ApiProperty({ description: '刷新令牌' })
  @IsString()
  @IsJWT()
  refreshToken: string

  @ApiPropertyOptional({ description: '设备信息' })
  @IsOptional()
  @ValidateNested()
  @Type(() => DeviceInfoDto)
  deviceInfo?: DeviceInfoDto
}

/**
 * 忘记密码DTO
 */
export class ForgotPasswordDto {
  @ApiProperty({ description: '邮箱地址' })
  @IsEmail()
  email: string

  @ApiPropertyOptional({ description: '验证码' })
  @IsOptional()
  @IsString()
  @MaxLength(10)
  captcha?: string

  @ApiPropertyOptional({ description: '验证码令牌' })
  @IsOptional()
  @IsString()
  captchaToken?: string
}

/**
 * 重置密码DTO
 */
export class ResetPasswordDto {
  @ApiProperty({ description: '重置令牌' })
  @IsString()
  token: string

  @ApiProperty({ description: '新密码' })
  @IsString()
  @IsStrongPassword()
  @MinLength(8)
  @MaxLength(128)
  newPassword: string

  @ApiProperty({ description: '确认新密码' })
  @IsString()
  confirmNewPassword: string

  @ApiPropertyOptional({ description: '设备信息' })
  @IsOptional()
  @ValidateNested()
  @Type(() => DeviceInfoDto)
  deviceInfo?: DeviceInfoDto
}

/**
 * 修改密码DTO
 */
export class ChangePasswordDto {
  @ApiProperty({ description: '当前密码' })
  @IsString()
  @MinLength(1)
  currentPassword: string

  @ApiProperty({ description: '新密码' })
  @IsString()
  @IsStrongPassword()
  @MinLength(8)
  @MaxLength(128)
  newPassword: string

  @ApiProperty({ description: '确认新密码' })
  @IsString()
  confirmNewPassword: string

  @ApiPropertyOptional({ description: '撤销所有会话' })
  @IsOptional()
  @IsBoolean()
  revokeAllSessions?: boolean
}

/**
 * 邮箱验证DTO
 */
export class VerifyEmailDto {
  @ApiProperty({ description: '验证令牌' })
  @IsString()
  token: string

  @ApiPropertyOptional({ description: '邮箱地址（可选验证）' })
  @IsOptional()
  @IsEmail()
  email?: string
}

/**
 * 重发验证邮件DTO
 */
export class ResendVerificationDto {
  @ApiProperty({ description: '邮箱地址' })
  @IsEmail()
  email: string

  @ApiPropertyOptional({ description: '验证码' })
  @IsOptional()
  @IsString()
  @MaxLength(10)
  captcha?: string

  @ApiPropertyOptional({ description: '验证码令牌' })
  @IsOptional()
  @IsString()
  captchaToken?: string
}

/**
 * 双因素认证设置DTO
 */
export class TwoFactorSetupDto {
  @ApiProperty({ description: '双因素认证密钥' })
  @IsString()
  secret: string

  @ApiProperty({ description: '验证码' })
  @IsString()
  @Matches(/^\d{6}$/)
  code: string

  @ApiPropertyOptional({ description: '备用恢复码' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  @ArrayMinSize(8)
  @ArrayMaxSize(10)
  backupCodes?: string[]
}

/**
 * 双因素认证验证DTO
 */
export class TwoFactorVerifyDto {
  @ApiProperty({ description: '验证码或备用恢复码' })
  @IsString()
  code: string

  @ApiPropertyOptional({ description: '是否为备用恢复码' })
  @IsOptional()
  @IsBoolean()
  isBackupCode?: boolean

  @ApiPropertyOptional({ description: '记住此设备' })
  @IsOptional()
  @IsBoolean()
  rememberDevice?: boolean
}

/**
 * 第三方登录DTO
 */
export class SocialLoginDto {
  @ApiProperty({ description: '认证提供商', enum: AuthProvider })
  @IsEnum(AuthProvider)
  provider: AuthProvider

  @ApiProperty({ description: '授权码或访问令牌' })
  @IsString()
  code: string

  @ApiPropertyOptional({ description: '重定向URI' })
  @IsOptional()
  @IsUrl()
  redirectUri?: string

  @ApiPropertyOptional({ description: '状态参数' })
  @IsOptional()
  @IsString()
  state?: string

  @ApiPropertyOptional({ description: '设备信息' })
  @IsOptional()
  @ValidateNested()
  @Type(() => DeviceInfoDto)
  deviceInfo?: DeviceInfoDto
}

/**
 * 绑定第三方账号DTO
 */
export class BindSocialAccountDto {
  @ApiProperty({ description: '认证提供商', enum: AuthProvider })
  @IsEnum(AuthProvider)
  provider: AuthProvider

  @ApiProperty({ description: '授权码或访问令牌' })
  @IsString()
  code: string

  @ApiPropertyOptional({ description: '重定向URI' })
  @IsOptional()
  @IsUrl()
  redirectUri?: string

  @ApiPropertyOptional({ description: '当前密码（安全验证）' })
  @IsOptional()
  @IsString()
  currentPassword?: string
}

/**
 * 解绑第三方账号DTO
 */
export class UnbindSocialAccountDto {
  @ApiProperty({ description: '认证提供商', enum: AuthProvider })
  @IsEnum(AuthProvider)
  provider: AuthProvider

  @ApiProperty({ description: '当前密码（安全验证）' })
  @IsString()
  currentPassword: string
}

/**
 * 验证访问令牌DTO
 */
export class ValidateTokenDto {
  @ApiProperty({ description: '访问令牌' })
  @IsString()
  @IsJWT()
  accessToken: string

  @ApiPropertyOptional({ description: '验证权限' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  permissions?: string[]

  @ApiPropertyOptional({ description: '验证角色' })
  @IsOptional()
  @IsArray()
  @IsEnum(UserRole, { each: true })
  roles?: UserRole[]
}

/**
 * 登录响应DTO
 */
export class LoginResponseDto {
  @ApiProperty({ description: '访问令牌' })
  @Expose()
  accessToken: string

  @ApiProperty({ description: '刷新令牌' })
  @Expose()
  refreshToken: string

  @ApiProperty({ description: '令牌类型' })
  @Expose()
  tokenType: string = 'Bearer'

  @ApiProperty({ description: '访问令牌过期时间（秒）' })
  @Expose()
  expiresIn: number

  @ApiProperty({ description: '刷新令牌过期时间（秒）' })
  @Expose()
  refreshExpiresIn: number

  @ApiProperty({ description: '用户信息' })
  @Expose()
  user: {
    id: string
    username: string
    email: string
    nickname?: string
    avatar?: string
    role: UserRole
    status: UserStatus
    emailVerified: boolean
    twoFactorEnabled: boolean
    lastLoginAt?: Date
  }

  @ApiPropertyOptional({ description: '权限列表' })
  @Expose()
  permissions?: string[]

  @ApiPropertyOptional({ description: '会话ID' })
  @Expose()
  sessionId?: string

  @ApiPropertyOptional({ description: '是否需要双因素认证' })
  @Expose()
  requiresTwoFactor?: boolean

  @ApiPropertyOptional({ description: '双因素认证临时令牌' })
  @Expose()
  twoFactorToken?: string

  @ApiPropertyOptional({ description: '首次登录标识' })
  @Expose()
  isFirstLogin?: boolean

  @ApiPropertyOptional({ description: '密码即将过期警告' })
  @Expose()
  passwordExpiryWarning?: {
    daysLeft: number
    message: string
  }
}

/**
 * 注册响应DTO
 */
export class RegisterResponseDto {
  @ApiProperty({ description: '用户ID' })
  @Expose()
  userId: string

  @ApiProperty({ description: '用户名' })
  @Expose()
  username: string

  @ApiProperty({ description: '邮箱地址' })
  @Expose()
  email: string

  @ApiProperty({ description: '注册状态' })
  @Expose()
  status: UserStatus

  @ApiProperty({ description: '是否需要邮箱验证' })
  @Expose()
  requiresEmailVerification: boolean

  @ApiPropertyOptional({ description: '验证邮件发送状态' })
  @Expose()
  verificationEmailSent?: boolean

  @ApiPropertyOptional({ description: '自动登录令牌（如果启用）' })
  @Expose()
  autoLoginToken?: string

  @ApiProperty({ description: '注册时间' })
  @Expose()
  registeredAt: Date

  @ApiPropertyOptional({ description: '邀请奖励信息' })
  @Expose()
  inviteReward?: {
    points: number
    message: string
  }
}

/**
 * 令牌刷新响应DTO
 */
export class RefreshTokenResponseDto {
  @ApiProperty({ description: '新访问令牌' })
  @Expose()
  accessToken: string

  @ApiProperty({ description: '新刷新令牌' })
  @Expose()
  refreshToken: string

  @ApiProperty({ description: '令牌类型' })
  @Expose()
  tokenType: string = 'Bearer'

  @ApiProperty({ description: '访问令牌过期时间（秒）' })
  @Expose()
  expiresIn: number

  @ApiProperty({ description: '刷新令牌过期时间（秒）' })
  @Expose()
  refreshExpiresIn: number

  @ApiPropertyOptional({ description: '会话ID' })
  @Expose()
  sessionId?: string

  @ApiPropertyOptional({ description: '用户基本信息' })
  @Expose()
  user?: {
    id: string
    username: string
    role: UserRole
    status: UserStatus
  }
}

/**
 * 双因素认证设置响应DTO
 */
export class TwoFactorSetupResponseDto {
  @ApiProperty({ description: '是否启用成功' })
  @Expose()
  enabled: boolean

  @ApiProperty({ description: '备用恢复码' })
  @Expose()
  backupCodes: string[]

  @ApiProperty({ description: 'QR码URL（首次设置）' })
  @Expose()
  qrCodeUrl?: string

  @ApiProperty({ description: '密钥（首次设置）' })
  @Expose()
  secret?: string

  @ApiProperty({ description: '设置时间' })
  @Expose()
  enabledAt: Date
}

/**
 * 会话信息DTO
 */
export class SessionInfoDto extends BaseDto {
  @ApiProperty({ description: '会话ID' })
  @Expose()
  sessionId: string

  @ApiProperty({ description: '用户ID' })
  @Expose()
  userId: string

  @ApiProperty({ description: '会话状态', enum: SessionStatus })
  @Expose()
  status: SessionStatus

  @ApiProperty({ description: 'IP地址' })
  @Expose()
  ipAddress: string

  @ApiProperty({ description: '用户代理' })
  @Expose()
  userAgent: string

  @ApiPropertyOptional({ description: '设备信息' })
  @Expose()
  deviceInfo?: DeviceInfoDto

  @ApiProperty({ description: '登录时间' })
  @Expose()
  loginAt: Date

  @ApiProperty({ description: '最后活动时间' })
  @Expose()
  lastActiveAt: Date

  @ApiProperty({ description: '过期时间' })
  @Expose()
  expiresAt: Date

  @ApiProperty({ description: '是否为当前会话' })
  @Expose()
  isCurrent: boolean

  @ApiProperty({ description: '是否记住登录' })
  @Expose()
  rememberMe: boolean

  @ApiPropertyOptional({ description: '地理位置' })
  @Expose()
  location?: {
    country: string
    region: string
    city: string
    latitude?: number
    longitude?: number
  }

  @ApiPropertyOptional({ description: '撤销时间' })
  @Expose()
  revokedAt?: Date

  @ApiPropertyOptional({ description: '撤销原因' })
  @Expose()
  revokeReason?: string
}

/**
 * 安全日志DTO
 */
export class SecurityLogDto extends BaseDto {
  @ApiProperty({ description: '日志类型' })
  @Expose()
  type: string

  @ApiProperty({ description: '事件描述' })
  @Expose()
  event: string

  @ApiProperty({ description: '详细信息' })
  @Expose()
  details: Record<string, any>

  @ApiProperty({ description: 'IP地址' })
  @Expose()
  ipAddress: string

  @ApiProperty({ description: '用户代理' })
  @Expose()
  userAgent: string

  @ApiProperty({ description: '风险等级' })
  @Expose()
  riskLevel: 'low' | 'medium' | 'high' | 'critical'

  @ApiProperty({ description: '是否成功' })
  @Expose()
  success: boolean

  @ApiPropertyOptional({ description: '错误信息' })
  @Expose()
  error?: string

  @ApiPropertyOptional({ description: '地理位置' })
  @Expose()
  location?: {
    country: string
    region: string
    city: string
  }

  @ApiPropertyOptional({ description: '设备信息' })
  @Expose()
  deviceInfo?: DeviceInfoDto

  @ApiPropertyOptional({ description: '会话ID' })
  @Expose()
  sessionId?: string
}

/**
 * 撤销会话DTO
 */
export class RevokeSessionDto {
  @ApiPropertyOptional({ description: '会话ID（不提供则撤销当前会话）' })
  @IsOptional()
  @IsUUID()
  sessionId?: string

  @ApiPropertyOptional({ description: '撤销原因' })
  @IsOptional()
  @IsString()
  @MaxLength(200)
  reason?: string

  @ApiPropertyOptional({ description: '是否撤销所有会话' })
  @IsOptional()
  @IsBoolean()
  revokeAll?: boolean

  @ApiPropertyOptional({ description: '是否排除当前会话' })
  @IsOptional()
  @IsBoolean()
  excludeCurrent?: boolean
}

/**
 * 查询安全日志DTO
 */
export class QuerySecurityLogDto extends PaginationDto {
  @ApiPropertyOptional({ description: '日志类型' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  types?: string[]

  @ApiPropertyOptional({ description: '风险等级' })
  @IsOptional()
  @IsArray()
  @IsEnum(['low', 'medium', 'high', 'critical'], { each: true })
  riskLevels?: string[]

  @ApiPropertyOptional({ description: '是否成功' })
  @IsOptional()
  @Transform(({ value }) => value === 'true')
  @IsBoolean()
  success?: boolean

  @ApiPropertyOptional({ description: '开始时间' })
  @IsOptional()
  @IsDateString()
  startDate?: string

  @ApiPropertyOptional({ description: '结束时间' })
  @IsOptional()
  @IsDateString()
  endDate?: string

  @ApiPropertyOptional({ description: 'IP地址' })
  @IsOptional()
  @IsString()
  ipAddress?: string

  @ApiPropertyOptional({ description: '搜索关键词' })
  @IsOptional()
  @IsString()
  @MaxLength(100)
  search?: string = ''
}

/**
 * 验证码DTO
 */
export class CaptchaDto {
  @ApiPropertyOptional({ description: '验证码类型' })
  @IsOptional()
  @IsEnum(['image', 'audio', 'sms', 'email'])
  type?: string = 'image'

  @ApiPropertyOptional({ description: '验证码难度' })
  @IsOptional()
  @IsEnum(['easy', 'medium', 'hard'])
  difficulty?: string = 'medium'

  @ApiPropertyOptional({ description: '验证码长度' })
  @IsOptional()
  @IsInt()
  @Min(4)
  @Max(8)
  length?: number = 4

  @ApiPropertyOptional({ description: '手机号（短信验证码）' })
  @IsOptional()
  @IsPhoneNumber('CN')
  phone?: string

  @ApiPropertyOptional({ description: '邮箱（邮件验证码）' })
  @IsOptional()
  @IsEmail()
  email?: string
}

/**
 * 验证码响应DTO
 */
export class CaptchaResponseDto {
  @ApiProperty({ description: '验证码令牌' })
  @Expose()
  token: string

  @ApiPropertyOptional({ description: '验证码图片（Base64）' })
  @Expose()
  image?: string

  @ApiPropertyOptional({ description: '验证码音频URL' })
  @Expose()
  audioUrl?: string

  @ApiProperty({ description: '过期时间（秒）' })
  @Expose()
  expiresIn: number

  @ApiProperty({ description: '创建时间' })
  @Expose()
  createdAt: Date

  @ApiPropertyOptional({ description: '发送状态（短信/邮件）' })
  @Expose()
  sent?: boolean

  @ApiPropertyOptional({ description: '发送目标（脱敏）' })
  @Expose()
  target?: string
}
